#include "c-utils/internal/ringbuf.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

typedef struct
{
    uint32_t size;
    unsigned char buf[0];
} node_t;

#define RINGBUF_MAX_SLOT (8)
typedef struct
{
    void *buf;
    uint32_t capacity;
    uint8_t slot_head;
    void *free_head;
    uint8_t slot_tail;
    void *slot[RINGBUF_MAX_SLOT];
    bool override;
} hdl_t;

ringbuf_t *utils_ringbuf_init(uint32_t nsize, bool override)
{
    // 申请空间取8倍数
    uint8_t m = nsize % 8;
    if (m != 0)
        nsize += (8 - m);

    void *buf = malloc(nsize);

    if (buf == NULL)
        return NULL;
    hdl_t *rb = (hdl_t *)calloc(1, sizeof(hdl_t));
    if (rb == NULL)
        return NULL;
    rb->buf = buf;
    rb->free_head = buf;
    rb->capacity = nsize;
    rb->override = override;
    return (ringbuf_t *)rb;
}

void utils_ringbuf_destroy(ringbuf_t *hdl)
{
    free(((hdl_t *)hdl)->buf);
    memset((hdl_t *)hdl, 0, sizeof(hdl_t));
    free(hdl);
    return;
}

void *ringbuf_malloc_override(hdl_t *rb, uint32_t nsize)
{
    void *b = NULL;
    if ((rb->buf + rb->capacity - rb->free_head) < nsize)
        b = rb->buf;
    else
        b = rb->free_head;
    rb->free_head = b + nsize;
    return b;
}

void *ringbuf_malloc_calc(hdl_t *rb, uint32_t nsize)
{
    void *b = NULL;
    void *head = rb->slot[rb->slot_head];
    if (head < rb->free_head)
    {
        if (head != NULL)
        {

            if ((rb->buf + rb->capacity - rb->free_head) < nsize)
            {
                if ((head - rb->buf) < nsize)
                    return NULL;
                b = rb->buf;
            }
            else
                b = rb->free_head;
        }
        else
            b = rb->buf;
    }
    else
    {
        if ((head - rb->free_head) < nsize)
            return NULL;
        b = rb->free_head;
    }
    rb->free_head = b + nsize;
    rb->slot[rb->slot_tail] = b;
    rb->slot_tail = (rb->slot_tail + 1) % RINGBUF_MAX_SLOT;

    if (b < rb->buf)
    {
        printf("!!!!! fuck @!!!!\n");
        exit(1);
    }

    if ((rb->buf + rb->capacity) < b)
    {
        printf("!!@!!!! shit !!!!! \n");
        exit(1);
    }

    return b;
}

void *utils_ringbuf_malloc(ringbuf_t *hdl, uint32_t nsize)
{
    hdl_t *rb = (hdl_t *)hdl;
    if (rb->capacity < nsize)
        return NULL;
    if (rb->override)
        return ringbuf_malloc_override(rb, nsize);
    return ringbuf_malloc_calc(rb, nsize);
}

#define unlikely(expr) __builtin_expect(!!(expr), 0)
#define likely(expr) __builtin_expect(!!(expr), 1)
void utils_ringbuf_free(ringbuf_t *r, void *buf)
{
    hdl_t *rb = (hdl_t *)r;
    if (rb->override)
        return;
    if (unlikely(rb->slot[rb->slot_head] != buf))
    {
        uint8_t i;
        bool found = false;
        for (i = 0; i < RINGBUF_MAX_SLOT; i++)
        {
            if (rb->slot[i] == buf)
            {
                rb->slot_head = i;
                found = true;
            }
        }
        if (false == found)
            printf("not found match buf\n");
    }
    rb->slot[rb->slot_head] = NULL;
    rb->slot_head = (rb->slot_head + 1) % RINGBUF_MAX_SLOT;
    return;
}